package com.cn.fw4j.mvc.servlet.impl;

import groovy.lang.GroovyObject;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.cn.fw4j.container.impl.GroovyController;
import com.cn.fw4j.container.impl.JavaController;
import com.cn.fw4j.container.impl.Scanning;
import com.cn.fw4j.container.inter.IContainer;
import com.cn.fw4j.container.inter.IController;
import com.cn.fw4j.ioc.ObjectHandle;
import com.cn.fw4j.ioc.annotation.Fw4jSpringIoc;
import com.cn.fw4j.ioc.impl.Fw4jSpringPlugs;
import com.cn.fw4j.ioc.inter.IFw4jSpringPlugs;
import com.cn.fw4j.json.inter.IFw4jJson;
import com.cn.fw4j.mvc.annotation.Fw4jController;
import com.cn.fw4j.mvc.page.inter.IPageTemplate;
import com.cn.fw4j.mvc.servlet.inter.IDispatcherHandle;
import com.cn.fw4j.util.ClassHelper;
import com.cn.fw4j.util.GroovyLoaderHelper;
import com.cn.fw4j.util.OutMap;
import com.cn.fw4j.util.OutParameter;

/**
 * 调度器 
 * @author murenchao
 *
 */
public final class DispatcherHandle implements IDispatcherHandle{
	private final static Logger logger = LoggerFactory.getLogger(DispatcherHandle.class);
	private final static GroovyLoaderHelper groovy = GroovyLoaderHelper.getInstance();
	static{
		logger.info("Start DispatcharServlet!!!");
		IContainer ic = new Scanning();
		ic.register(new JavaController());
		ic.register(new GroovyController());
		ic.run();
	}
	 /**
	  * 调度器
	  * @param method
	  * @param request
	  * @param response
	  */
     public void start(String method,HttpServletRequest request,HttpServletResponse response) {
    	 try{
			 request.setCharacterEncoding("UTF-8");
	    	 if(method.equals("get")){
	    		 get(request,response);
	    	 }else if(method.equals("post")){
		    	 String _method = request.getParameter("_method");
		    	 if(_method != null && method.equals("put")){
		    		 put(request,response);
		    	 }else if(_method != null && method.equals("delete")){
		    		 delete(request,response);
		    	 }else{
		    		 post(request,response);
		    	 }
	    	 }else if(method.equals("put")){
	    		 put(request,response);
	    	 }else if(method.equals("delete")){
	    		 delete(request,response);
	    	 }
    	 }catch(Exception e){
    		 e.printStackTrace();
    	 }
     }
     
     private static String basePath(HttpServletRequest request){
    	 return request.getContextPath();
     }
     private static String urlPath(HttpServletRequest request){
    	 String base = basePath(request);
    	 String url = request.getRequestURI();
    	 if(!base.equals("/")){
    		 url = url.replace(base, "");
    	 }
    	 return url;
     }
     /**
      * GET 获取
      * @param request
      * @param response
      */
     public void get(HttpServletRequest request,HttpServletResponse response){
    	 String urlPath = "GET$"+urlPath(request);
    	 logger.info(urlPath);
    	 IController ioc = new JavaController(); 
    	 String call = ioc.gets(urlPath);
    	 if(call != null){
      		JavaController(request, response, call);
      	 }else{
  	    	 ioc = new GroovyController(); 
  	    	 call = ioc.gets(urlPath);
  	    	 if(call != null){
  	    		 GroovyController(request, response, call);
  	    	 }else{
  	    		 try {
  					response.sendError(404);
  				} catch (IOException e) {
  					e.printStackTrace();
  				}
  	    	 }
      	 }
     }

	
     /**
      * POST 添加
      * @param request
      * @param response
      */
     public void post(HttpServletRequest request,HttpServletResponse response){
    	 String urlPath = "POST$"+urlPath(request);
    	 logger.info(urlPath);
    	 IController ioc = new JavaController(); 
    	 String call = ioc.posts(urlPath);
    	 if(call != null){
    		JavaController(request, response, call);
    	 }else{
	    	 ioc = new GroovyController(); 
	    	 call = ioc.posts(urlPath);
	    	 if(call != null){
	    		 GroovyController(request, response, call);
	    	 }else{
	    		 try {
					response.sendError(404);
				} catch (IOException e) {
					e.printStackTrace();
				}
	    	 }
    	 }
    	 
     }
     /**
      * PUT 修改
      * @param request
      * @param response
      */
     public void put(HttpServletRequest request, HttpServletResponse response){
    	 String urlPath = "PUT$"+urlPath(request);
    	 logger.info(urlPath);
    	 IController ioc = new JavaController(); 
    	 String call = ioc.puts(urlPath);
    	 if(call != null){
     		JavaController(request, response, call);
     	 }else{
 	    	 ioc = new GroovyController(); 
 	    	 call = ioc.puts(urlPath);
 	    	 if(call != null){
 	    		 GroovyController(request, response, call);
 	    	 }else{
 	    		 try {
 					response.sendError(404);
 				} catch (IOException e) {
 					e.printStackTrace();
 				}
 	    	 }
     	 }
     }
     /**
      * DELETE 删除
      * @param request
      * @param response
      */
     public void delete(HttpServletRequest request,HttpServletResponse response){
    	 String urlPath = "DELTETE$"+urlPath(request);
    	 logger.info(urlPath);
    	 IController ioc = new JavaController(); 
    	 String call = ioc.deletes(urlPath);
    	 if(call != null){
      		JavaController(request, response, call);
      	 }else{
  	    	 ioc = new GroovyController(); 
  	    	 call = ioc.deletes(urlPath);
  	    	 if(call != null){
  	    		 GroovyController(request, response, call);
  	    	 }else{
  	    		 try {
  					response.sendError(404);
  				} catch (IOException e) {
  					e.printStackTrace();
  				}
  	    	 }
      	 }
     }
     
     /**
      * 调用Groovy Controller
      * @param request
      * @param response
      * @param call
      */
     private void GroovyController(HttpServletRequest request,
 			HttpServletResponse response, String call) {
 		String[] c  = call.split("[$]");
     	 try {
 			Class<?> cl = groovy.getGroovyClass(c[0]);
 			String template = cl.getAnnotation(Fw4jController.class).value();
 			Method m = ClassHelper.getMethod(cl.getMethods(), c[1]);
 			if(m != null){
				Fw4jSpringIoc ioc = m.getAnnotation(Fw4jSpringIoc.class);
 				OutParameter<Object,Object> out = new OutMap<Object,Object>();
 				List<Object> args = parameters(request, response, m,out,ioc);
 				GroovyObject go = groovy.getGroovyInstance(c[0]);
				ObjectHandle.decorator(m, args);
 				Object obj = go.invokeMethod(c[1], args);
				if(ioc!=null && out.containsKey(ioc.value())){
					out.remove(ioc.value());
				}
 				if(c.length>2)
 					printJson(response, c[2], obj);
 				String path = obj.equals(String.class) ? obj.toString() : null;
				if(path != null && (path.startsWith("request:") 
						|| path.startsWith("redirect:"))){
					Class<?> pcl = ClassHelper.loadClass(template);
					IPageTemplate ipt = (IPageTemplate) pcl.newInstance();
					ipt.Template(path, out, request, response);
				}
 			}
 		} catch (Exception e) {
 			e.printStackTrace();
		}
 	}
     
    /**
     * 组织参数
     * @param request
     * @param response
     * @param m
     * @return
     */
	private List<Object> parameters(HttpServletRequest request,
			HttpServletResponse response, Method m,
			OutParameter<Object,Object> out,Fw4jSpringIoc ioc) {
		Class<?>[] paramTypes = m.getParameterTypes();
		List<Object> params = new ArrayList<Object>(); 
		if(ioc !=null && !ioc.value().equals("")) {
			IFw4jSpringPlugs springPlugs = new Fw4jSpringPlugs();
			out.put(ioc, springPlugs.getBean(ioc.value()));
		}
		for(Class<?> type : paramTypes){
			if(type.equals(HttpServletRequest.class)){
				params.add(request);
			}else if(type.equals(HttpServletResponse.class)){
				params.add(response);
			}else if(type.equals(HashMap.class)){
				params.add(new HashMap<Object,Object>());
			}else if(type.equals(ArrayList.class)){
				params.add(new ArrayList<Object>());
			}else if(type.equals(LinkedHashMap.class)){
				params.add(new LinkedHashMap<Object,Object>());
			}else if(type.equals(Set.class)){
				params.add(new LinkedHashSet<Object>());
			}else if(type.equals(OutMap.class) || type.equals(OutParameter.class)){
				params.add(out);
			}
		}
		return params;
	}

     /**
      * 调用 Java Controller
      * @param request
      * @param response
      * @param call
      */
 	private void JavaController(HttpServletRequest request,
 			HttpServletResponse response, String call) {
 		try {
 			String[] c  = call.split("[$]");
 			Class<?> cl = ClassHelper.loadClass(c[0]);
 			String template = cl.getAnnotation(Fw4jController.class).value();
 			Object instance = ObjectHandle.newInstance(cl);
 			Method m = ClassHelper.getMethod(cl.getMethods(), c[1]);
 			if(m != null){
 				Fw4jSpringIoc ioc = m.getAnnotation(Fw4jSpringIoc.class);
 				OutParameter<Object,Object> out = new OutMap<Object,Object>();
 				List<Object> args = parameters(request, response, m,out,ioc);
				ObjectHandle.decorator(m, args);
				Object obj = m.invoke(instance,args.toArray());
				if(ioc !=null && out.containsKey(ioc.value())){
					out.remove(ioc.value());
				}
				if(c.length>2)
					printJson(response, c[2], obj);
 				String path = obj.equals(String.class) ? obj.toString() : null;
				if(path != null && (path.startsWith("request:") 
						|| path.startsWith("redirect:"))){
					Class<?> pcl = ClassHelper.loadClass(template);
					IPageTemplate ipt = (IPageTemplate) pcl.newInstance();
					ipt.Template(path, out, request, response);
				}
 			}
 		} catch (Exception e){
 			e.printStackTrace();
 		}
 	}
 	
 	private void printJson(HttpServletResponse response, String c,
			Object obj) throws InstantiationException, IllegalAccessException,
			ClassNotFoundException, IOException {
		if(c.startsWith("JSON:")){
			String json = c.replace("JSON:", "");
			logger.debug(json);
			IFw4jJson ifw4jJson = (IFw4jJson)Class.forName(json).newInstance();
			response.getOutputStream().print(ifw4jJson.toJson(obj));
		}
	}
}
